package com.gobrs.async.core.engine;

import com.gobrs.async.core.GobrsAsync;
import com.gobrs.async.core.TaskReceive;
import com.gobrs.async.core.anno.Task;
import com.gobrs.async.core.common.def.Constant;
import com.gobrs.async.core.common.exception.GobrsAsyncException;
import com.gobrs.async.core.config.GobrsAsyncProperties;
import com.gobrs.async.core.config.RuleConfig;
import com.gobrs.async.core.holder.BeanHolder;
import com.gobrs.async.core.task.AsyncTask;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;

import static com.gobrs.async.core.common.def.DefaultConfig.*;

/**
 * 规则解析引擎
 */
public class RuleParseEngine<T> extends AbstractEngine {

    @Resource
    private GobrsAsyncProperties gobrsAsyncProperties;

    @Resource
    private GobrsAsync gobrsAsync;

    @Override
    public void doParse(RuleConfig rule, boolean reload) {
        // 替换空白字符(\s)
        String[] taskFlows = rule.getContent().replaceAll("\\s+", "").split(gobrsAsyncProperties.getSplit());
        // 找出任务流头节点集合：(AService,BService,CService->DService) -> AService,BService,CService
        List<AsyncTask> pioneer = new ArrayList<>();
        for (String taskFlow : taskFlows) {
            String[] taskArr = taskFlow.split(gobrsAsyncProperties.getPoint());
            if (taskArr.length == 0) {
                throw new GobrsAsyncException("com.gobrs.async.rule com.gobrs.async.config error !!!");
            }
            String door = taskArr[0];
            if (door.contains(Constant.sp)) {
                String[] childFlows = door.split(Constant.sp);
                for (String cf : childFlows) {
                    AsyncTask asyncTask = EngineExecutor.getAsyncTask(cf);
                    pioneer.add(asyncTask);
                }
            } else {
                pioneer.add(EngineExecutor.getAsyncTask(door));
            }
        }

        // 开始构建任务流并添加任务流头节点, 一条规则对应一个TaskFlow
        gobrsAsync.begin(rule.getName(), pioneer, reload);

        // 缓存非头任务以外的任务 TaskName -> AsyncTask
        Map<String, AsyncTask> cacheTaskWrappers = new HashMap<>();
        for (String taskFlow : taskFlows) {
            // 根据规则解析任务
            String[] taskArr = taskFlow.split(gobrsAsyncProperties.getPoint());
            List<String> arrayList = Arrays.asList(taskArr);
            String leftTaskName = arrayList.get(0);
            TaskReceive taskReceive;
            if (leftTaskName.contains(Constant.sp)) {
                String[] split = leftTaskName.split(Constant.sp);
                for (String s : split) {
                    // 规则头节点集合处理(TaskReceive)之后的 组内头节点处理(TaskReceive)
                    taskReceive = gobrsAsync.after(rule.getName(), EngineExecutor.getAsyncTask(s));
                    // 组内头节点(TaskReceive)的子节点处理
                    doChildFlow(taskReceive, cacheTaskWrappers, arrayList);
                }
            } else {
                // 设置子任务
                taskReceive = gobrsAsync.after(rule.getName(), EngineExecutor.getAsyncTask(leftTaskName));
                doChildFlow(taskReceive, cacheTaskWrappers, arrayList);
            }
        }
    }

    private void doChildFlow(TaskReceive taskReceive, Map<String, AsyncTask> cacheTaskWrappers, List<String> arrayList) {
        for (int i = 1; i < arrayList.size(); i++) {
            String taskBean = arrayList.get(i);
            // 解析任务规则
            if (taskBean.contains(Constant.sp)) {
                String[] beanArray = taskBean.split(Constant.sp);
                List<String> beanList = Arrays.asList(beanArray);
                // 从规则引擎加载任务
                List<AsyncTask> asyncTasks = new ArrayList<>();
                for (String bean : beanList) {
                    asyncTasks.add(EngineExecutor.getWrapperDepend(cacheTaskWrappers, bean, taskReceive, false));
                }
                taskReceive.refresh(asyncTasks);
            } else {
                EngineExecutor.getWrapperDepend(cacheTaskWrappers, taskBean, taskReceive, true);
            }
        }
    }

    /**
     * 引擎执行器主要负责获取任务和设置任务处理者
     */
    static class EngineExecutor {

        /**
         * 组装任务
         */
        private static AsyncTask getAsyncTask(String taskName) {
            String name = taskName;
            int cursor = 0;
            String[] preNamed = taskName.split(Constant.tied);
            if (taskName.contains(Constant.tied)) {
                String[] tiredNames = preNamed;
                name = tiredNames[0];
                cursor = tiredNames.length;
            }
            AsyncTask task = (AsyncTask) getBean(name);

            // 解析注解配置
            task.setDesc(getTaskAnnotation(task, (anno) -> task.getDesc(), String.class));
            task.setCallback(getTaskAnnotation(task, (anno) -> task.isCallback(), Boolean.class));
            task.setRetryCount(getTaskAnnotation(task, (anno) -> task.getRetryCount(), Integer.class));
            task.setFailSubExec(getTaskAnnotation(task, (anno) -> task.isFailSubExec(), Boolean.class));
            String annotionTaskName = getTaskAnnotation(task, (anno) -> task.getName(), String.class);

            if (!StringUtils.isEmpty(annotionTaskName)) {
                task.setName(annotionTaskName);
            } else {
                task.setName(taskName);
            }

            if (taskName.contains(Constant.tied) && RULE_ANY.equals(preNamed[1])) {
                task.setAny(true);
            }

            if (taskName.contains(Constant.tied) && RULE_ANY_CONDITION.equals(preNamed[1])) {
                task.setAnyCondition(true);
            }

            if (cursor == 3 && RULE_EXCLUSIVE.equals(preNamed[2])) {
                task.setExclusive(true);
            }
            return task;
        }

        public static AsyncTask getWrapperDepend(Map<String, AsyncTask> cacheTaskWrappers, String taskBean, TaskReceive taskReceive, boolean clear) {
            /**
             * 解析任务规则配置
             */
            return Optional.of(getAsyncTask(taskBean))
                    .map(bean ->
                            Optional.ofNullable(cacheTaskWrappers.get(taskBean))
                            .map((tk) -> {
                                taskReceive.then(clear, tk);
                                return tk;
                            }).orElseGet(() -> {
                                /**
                                 * 加载任务
                                 */
                                AsyncTask asyncTask = getAsyncTask(taskBean);
                                cacheTaskWrappers.put(taskBean, asyncTask);
                                /**
                                 * 设置子任务
                                 */
                                taskReceive.then(clear, asyncTask);
                                return asyncTask;
                            }))
                    .orElse(null);
        }

        public static Object getBean(String bean) {
            return Optional.ofNullable(BeanHolder.getBean(bean)).orElseThrow(() -> new RuntimeException("bean not found, name is " + bean));
        }

        private static <T> T getTaskAnnotation(AsyncTask task, Function<Task, T> function, Class<T> tClass) {
            Task annotation = task.getClass().getAnnotation(Task.class);
            return function.apply(annotation);
        }
    }

}
